﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Abp.Extensions;
using Abp.Json;
using Abp.UI;
using Castle.Core.Logging;
using Magicodes.AppSession;
using Magicodes.WeChat.Application.Pay.Dto;
using Magicodes.WeChat.SDK;
using Magicodes.WeChat.SDK.Pays;
using Magicodes.WeChat.SDK.Pays.TenPayV3;
using Microsoft.AspNetCore.Http;
using Magicodes.WeChat.SDK.Core.Pays.TenPayV3;
using Abp.Runtime.Session;
using Magicodes.WeChat.User;
using Abp.Application.Services;

namespace Magicodes.WeChat.Application.Pay
{
    public class WeChatPayAppService : IWeChatPayAppService
    {

        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IAppSession _appSession;
        private readonly IWeChatUserAppService _weChatUserAppService;

        public IAbpSession AbpSession { get; set; }

        private static string[] AllTradeTypes = new string[] { "JSAPI", "MWEB", "APP", "NATIVE" };


        public WeChatPayAppService(
            IAppSession appSession,
            IHttpContextAccessor httpContextAccessor,
            IWeChatUserAppService weChatUserAppService)
        {
            _appSession = appSession;
            _httpContextAccessor = httpContextAccessor;
            AbpSession = NullAbpSession.Instance;
            _weChatUserAppService = weChatUserAppService;
        }

        public ILogger Logger { get; set; }

        /// <summary>
        /// 统一下单支付
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<Dictionary<string, string>> ToPay(ToPayInput input)
        {
            Logger.Info("准备发起支付:" + input.ToJsonString());
            string clientIp = null;
            //H5支付需要实际IP
            if (clientIp.IsNullOrWhiteSpace())
            {
                clientIp = _httpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString();
            }

            if (clientIp.IsNullOrWhiteSpace())
            {
                clientIp = "8.8.8.8";
            }

            #region 设置交易类型
            var tradeType = "JSAPI";
            if (input.TradeType.HasValue)
            {
                tradeType = AllTradeTypes[(int)input.TradeType];
            }
            else
            {
                tradeType = _appSession.AppSessionInfo.RequestType == RequestTypes.WeChat ? "JSAPI" : "MWEB";
            }
            #endregion

            //如果AbpSession.UserId存在内容，则自动添加uid=userId到CustomData，以便于支付回调
            string openId = input.OpenId;
            if (AbpSession.UserId.HasValue)
            {
                if (input.CustomData.IsNullOrWhiteSpace())
                {
                    input.CustomData = new { uid = AbpSession.UserId.Value }.ToJsonString();
                }
                else if (input.CustomData.EndsWith("}"))
                {
                    input.CustomData = input.CustomData.Replace("}", ",\"uid\":" + AbpSession.UserId.Value + "}");
                }
                //如果openid为空，则自动获取关联的粉丝信息得到openId
                if (openId.IsNullOrWhiteSpace())
                {
                    var weChatUser = await _weChatUserAppService.GetWeChatUserByUserId(AbpSession.UserId.Value.ToString());
                    if (weChatUser != null)
                    {
                        openId = weChatUser.Id;
                    }
                }
            }
            //其他支付模式，自动添加UserId传值
            else if (_appSession.AppSessionInfo.RequestType != RequestTypes.WeChat)
            {
                var userId = _appSession.AppSessionInfo.AppUserId;
                if (input.CustomData.IsNullOrWhiteSpace())
                {
                    input.CustomData = new { uid = userId }.ToJsonString();
                }
                else if (input.CustomData.EndsWith("}"))
                {
                    input.CustomData = input.CustomData.Replace("}", ",\"uid\":" + userId + "}");
                }
            }

            if (openId.IsNullOrWhiteSpace() && _appSession.AppSessionInfo.RequestType == RequestTypes.WeChat)
            {
                openId = _appSession.AppSessionInfo.AppUserId;
            }

            var model = new UnifiedorderRequest
            {
                //H5支付不需要填写OpenId
                OpenId = openId,
                SpbillCreateIp = clientIp,
                OutTradeNo = input.TradeNo.IsNullOrEmpty() ? PayUtil.GenerateOutTradeNo() : input.TradeNo,
                TotalFee = Convert.ToInt32(input.Amount * 100).ToString(),
                NonceStr = PayUtil.GetNoncestr(),
                TradeType = tradeType,
                Body = input.Remark,
                DeviceInfo = "WEB",
                Attach = input.CustomData
            };
            UnifiedorderResult result = null;
            if (tradeType != "JSAPI")
            {
                var sceneInfo = new SceneInfo()
                {
                    H5Info = new WapInfo()
                    {
                        WapName = input.WapName,
                        WapUrl = input.WapUrl
                    }
                };
                Logger.Info("生成UnifiedorderRequest:" + model.ToJsonString());
                result = WeChatApisContext.Current.TenPayV3Api.Unifiedorder(model, sceneInfo);
            }
            else
            {
                Logger.Info("生成UnifiedorderRequest:" + model.ToJsonString());
                result = WeChatApisContext.Current.TenPayV3Api.Unifiedorder(model);
            }

            if (result.ReturnCode == "FAIL")
                throw new UserFriendlyException(result.Message);
            var dict = new Dictionary<string, string>
            {
                {"appId", result.AppId},
                {"timeStamp", PayUtil.GetTimestamp()},
                {"nonceStr", result.NonceStr},
                {"package", "prepay_id=" + result.PrepayId},
                {"signType", "MD5"}
            };
            dict.Add("paySign", PayUtil.CreateMd5Sign(dict, WeChatConfigManager.Current.GetPayConfig().TenPayKey));
            if (_appSession.AppSessionInfo.RequestType != RequestTypes.WeChat)
            {
                dict.Add("mweb_url", result.MWebUrl);
            }
            Logger.Info("生成支付参数:" + dict.ToJsonString());
            return await Task.FromResult(dict);
        }

        /// <summary>
        /// 统一下单支付
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [RemoteService(IsEnabled = false)]
        public async Task<Dictionary<string, string>> CustomPay(CustomPayInput input)
        {
            Logger.Info("准备发起支付:" + input.ToJsonString());
            string clientIp = null;
            //H5支付需要实际IP
            if (clientIp.IsNullOrWhiteSpace())
            {
                clientIp = _httpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString();
            }
            clientIp = clientIp ?? "8.8.8.8";

            #region 设置交易类型
            var tradeType = "JSAPI";
            if (input.TradeType.HasValue)
            {
                tradeType = AllTradeTypes[(int)input.TradeType];
            }
            else
            {
                tradeType = _appSession.AppSessionInfo.RequestType == RequestTypes.WeChat ? "JSAPI" : "MWEB";
            }
            #endregion

            //如果AbpSession.UserId存在内容，则自动添加uid=userId到CustomData，以便于支付回调
            string openId = input.OpenId;
            if (AbpSession.UserId.HasValue)
            {
                if (input.CustomData.IsNullOrWhiteSpace())
                {
                    input.CustomData = new { uid = AbpSession.UserId.Value }.ToJsonString();
                }
                else if (input.CustomData.EndsWith("}"))
                {
                    input.CustomData = input.CustomData.Replace("}", ",\"uid\":" + AbpSession.UserId.Value + "}");
                }
                //如果openid为空，则自动获取关联的粉丝信息得到openId
                if (openId.IsNullOrWhiteSpace())
                {
                    var weChatUser = await _weChatUserAppService.GetWeChatUserByUserId(AbpSession.UserId.Value.ToString());
                    if (weChatUser != null)
                    {
                        openId = weChatUser.Id;
                    }
                }
            }
            //其他支付模式，自动添加UserId传值
            else if (_appSession.AppSessionInfo.RequestType != RequestTypes.WeChat)
            {
                var userId = _appSession.AppSessionInfo.AppUserId;
                if (input.CustomData.IsNullOrWhiteSpace())
                {
                    input.CustomData = new { uid = userId }.ToJsonString();
                }
                else if (input.CustomData.EndsWith("}"))
                {
                    input.CustomData = input.CustomData.Replace("}", ",\"uid\":" + userId + "}");
                }
            }

            if (openId.IsNullOrWhiteSpace() && _appSession.AppSessionInfo.RequestType == RequestTypes.WeChat)
            {
                openId = _appSession.AppSessionInfo.AppUserId;
            }

            var model = new UnifiedorderRequest
            {
                //H5支付不需要填写OpenId
                OpenId = openId,
                SpbillCreateIp = clientIp,
                OutTradeNo = input.TradeNo.IsNullOrEmpty() ? PayUtil.GenerateOutTradeNo() : input.TradeNo,
                TotalFee = Convert.ToInt32(input.Amount * 100).ToString(),
                NonceStr = PayUtil.GetNoncestr(),
                TradeType = tradeType,
                Body = input.Remark,
                DeviceInfo = "WEB",
                Attach = input.CustomData,
                AppId = input.AppId,
                MchId = input.MchId
            };
            UnifiedorderResult result = null;
            input.TenPayKey = input.TenPayKey ?? WeChatConfigManager.Current.GetPayConfig().TenPayKey;
            if (tradeType != "JSAPI")
            {
                var sceneInfo = new SceneInfo()
                {
                    H5Info = new WapInfo()
                    {
                        WapName = input.WapName,
                        WapUrl = input.WapUrl
                    }
                };
                Logger.Info("生成UnifiedorderRequest:" + model.ToJsonString());
                result = WeChatApisContext.Current.TenPayV3Api.Unifiedorder(model, sceneInfo, tenPayKey: input.TenPayKey);
            }
            else
            {
                Logger.Info("生成UnifiedorderRequest:" + model.ToJsonString());
                result = WeChatApisContext.Current.TenPayV3Api.Unifiedorder(model, tenPayKey: input.TenPayKey);
            }

            if (result.ReturnCode == "FAIL")
                throw new UserFriendlyException(result.Message);
            var dict = new Dictionary<string, string>
            {
                {"appId", result.AppId},
                {"timeStamp", PayUtil.GetTimestamp()},
                {"nonceStr", result.NonceStr},
                {"package", "prepay_id=" + result.PrepayId},
                {"signType", "MD5"}
            };
            dict.Add("paySign", PayUtil.CreateMd5Sign(dict, input.TenPayKey));
            if (_appSession.AppSessionInfo.RequestType != RequestTypes.WeChat)
            {
                dict.Add("mweb_url", result.MWebUrl);
            }
            Logger.Info("生成支付参数:" + dict.ToJsonString());
            return await Task.FromResult(dict);
        }
    }
}